package com.nbsaas.boot.datasource;

import com.nbsaas.boot.tenant.api.domain.response.DatabaseResponse;
import com.nbsaas.boot.tenant.api.domain.simple.DatabaseSimple;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import org.springframework.beans.BeanUtils;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

import static java.util.concurrent.TimeUnit.SECONDS;

public class DynamicDataSource extends AbstractRoutingDataSource {


    //InheritableThreadLocal
    private static final ThreadLocal<String> contextHolder = new InheritableThreadLocal<>();

    public static void setDataSourceKey(String key) {
        contextHolder.set(key);
    }

    public static void clearDataSourceKey() {
        contextHolder.remove();
    }
    public static String getDataSourceKey() {
       return contextHolder.get();
    }
    @Override
    protected Object determineCurrentLookupKey() {
        return contextHolder.get();
    }


    public void addDataSource(DatabaseSimple config) {
        DataSource dataSource =simple(config);
        if (testDataSource(dataSource)){
            setDataSource(config.getDomain(), dataSource);
        }

    }
    public void addDataSource(DatabaseResponse config) {
        DatabaseSimple database=new DatabaseSimple();
        BeanUtils.copyProperties(config,database);
        DataSource dataSource =simple(database);
        if (testDataSource(dataSource)){
            setDataSource(config.getDomain(), dataSource);
        }

    }
    public void setDataSource(String dataSourceKey, DataSource dataSource) {
        // 获取当前数据源映射
        Map<Object, DataSource> dataSources = this.getResolvedDataSources();
        // 创建一个新的 Map 对象，将原有数据源映射复制到新的 Map 中
        Map<Object, Object> newDataSources = new HashMap<>(dataSources);
        // 将新数据源添加到新的 Map 中
        newDataSources.put(dataSourceKey, dataSource);
        // 调用 setTargetDataSources 方法设置新的数据源映射
        this.setTargetDataSources(newDataSources);
        // 通知 AbstractRoutingDataSource 数据源映射已更新
        this.afterPropertiesSet();
    }

    public boolean testDataSource(DataSource dataSource) {
        try (Connection ignored = dataSource.getConnection()) {
            return true;
        } catch (SQLException e) {
            e.printStackTrace();
            return false;
        }
    }


    private static DataSource hikari(DatabaseSimple config) {

        HikariConfig hikariConfig = new HikariConfig();
        hikariConfig.setJdbcUrl(config.getUrl());
        hikariConfig.setUsername(config.getUsername());
        hikariConfig.setPassword(config.getPassword());
        hikariConfig.setDriverClassName(config.getDriverClassName());
        hikariConfig.setMaximumPoolSize(10);
        hikariConfig.setConnectionTimeout( SECONDS.toMillis(30));
        hikariConfig.setIdleTimeout(SECONDS.toMillis(60));
        hikariConfig.setMinimumIdle(1);

        return new HikariDataSource(hikariConfig);
    }
    private static DriverManagerDataSource simple (DatabaseSimple config) {

        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setUrl(config.getUrl());
        dataSource.setUsername(config.getUsername());
        dataSource.setPassword(config.getPassword());
        dataSource.setDriverClassName(config.getDriverClassName());

        return dataSource;
    }

}
